package com.reebake.ideal.document.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ZipUtil;
import com.reebake.ideal.document.entity.DocumentRenderFile;
import com.reebake.ideal.document.entity.DocumentRenderResult;
import com.reebake.ideal.document.service.DocumentRenderService;
import com.reebake.ideal.document.service.DocumentTemplatePlusService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.web.bind.annotation.*;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("document/template")
@RequiredArgsConstructor
public class DocumentTemplatePlusController {
    private final DocumentTemplatePlusService documentTemplatePlusService;
    private final DocumentRenderService documentRenderService;

    @SneakyThrows
    @PostMapping("render")
    public void render(@RequestParam String documentTemplateId, @RequestBody(required = false) Map<String, Object> data
    , HttpServletResponse response) {
        String dispositionType = "inline";
        DocumentRenderResult documentRenderResult = documentRenderService.render(documentTemplateId, data);
        DocumentRenderFile documentRenderFile = zip(documentRenderResult);
        if(documentRenderFile == null) {
            return;
        }
        String filename = URLEncoder.encode(documentRenderFile.getFilename(), StandardCharsets.UTF_8);
        String contentType = Files.probeContentType(Paths.get(filename));
        response.addHeader("Content-Disposition", dispositionType + "; filename=\"" + filename + "\"");
        response.setContentType(contentType);

        InputStream is = documentRenderFile.getInputStream();

        byte[] buffer = new byte[1024];
        int len = 0;
        OutputStream os = response.getOutputStream();

        try {
            while ((len = is.read(buffer)) != -1) {
                os.write(buffer, 0, len);
            }
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
        IoUtil.close(is);
        os.flush();
    }

    @SneakyThrows
    private DocumentRenderFile zip(DocumentRenderResult source) {
        if(CollUtil.isEmpty(source.getRenderedItems())){
            return null;
        }
        if(source.getRenderedItems().size() > 1){
            DocumentRenderFile documentRenderFile = new DocumentRenderFile();
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            List<String> paths = new ArrayList<>();
            List<InputStream> ins = new ArrayList<>();
            for(DocumentRenderFile result : source.getRenderedItems()){
                paths.add("/" + result.getFilename());
                ins.add(result.getInputStream());
            }
            ZipUtil.zip(bos, ArrayUtil.toArray(paths, String.class), ArrayUtil.toArray(ins, InputStream.class));
            bos.flush();
            documentRenderFile.setInputStream(new ByteArrayInputStream(bos.toByteArray()));
            bos.close();
            String outFilename = source.getRenderedItems().get(0).getFilename();
            outFilename = FileNameUtil.mainName(outFilename) + ".zip";
            documentRenderFile.setFilename(outFilename);

            return documentRenderFile;
        }
        return source.getRenderedItems().get(0);
    }
}
